﻿using System;
using System.IO;
using System.Linq;
using System.Xml;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using DiscoveryLogic.UI.Layouts.ContentScreens;
using DiscoveryLogic.UI.Layouts.Controls;
using System.Windows.Browser;
using DiscoveryLogic.DataServices.DataSources;
using DiscoveryLogic.UI.Layouts.Converters;
using DiscoveryLogic.UI.Layouts.CustomEventArgs;
using System.Windows.Markup;
using DiscoveryLogic.UI.Layouts.Models;

namespace DiscoveryLogic.UI.Layouts.Controls
{
    public class RadialAspect
    {
        #region Private Variables

        // The RadialItemControl that we are wrapping
        private readonly RadialItemControl _control;

        // The RadialItemControl's base name - we assume that all elements within the control are prefixed with this label, e.g. MyName_ATextBlockName
        private readonly string _controlName;

        // A reference to the screen aspect is on
        private View360 contentScreen;

        // Model
        private Account _model;

        #endregion

        #region Constructors

        public RadialAspect(string aspectName, View360 content)
        {
            // The aspects are XAML files consisting of a Canvas, and then a RadialItemControl within the Canvas.
            // Read the XAML, then initialise our wrapped control from the RadialItemControl on the XAML's canvas.
            System.IO.Stream stream = this.GetType().Assembly.GetManifestResourceStream(aspectName);
            Canvas view = XamlReader.Load(new System.IO.StreamReader(stream).ReadToEnd()) as Canvas;

            _control = view.Children[0] as RadialItemControl;

            // Remove the control from the Canvas so we can use it (the Canvas will be discarded anyway)
            view.Children.RemoveAt(0);

            // Get the name of the control
            _controlName = _control.Name;

            contentScreen = content;
        }

        #endregion

        #region Get/Set Properties

        // Get the wrapped control
        public RadialItemControl Control
        {
            get { return _control; }
        }

        // Get the associated model
        public Account Model
        {
            get { return _model; }
            set { _model = value;
                SetDetailsText();
            }
        }

        // Gets/sets the ZIndex property of this aspect
        private int ZIndex;

        public int ZOrder
        {
            get { return this.ZIndex; }
            set
            {
                this.ZIndex = value;
                _control.SetValue(Canvas.ZIndexProperty, value);
            }
        }

        // Title text Opacity
        private int TitleTextOpac = 1;

        public int TitleTextOpacity
        {
            get { return this.TitleTextOpac; }
            set
            {
                this.TitleTextOpac = value;
                TextBlock tb = _control.Label.FindName(String.Format("{0}_TitleText", _controlName)) as TextBlock;
                tb.Opacity = value;
            }
        }

        // Detail Text Line 1 Opacity
        private int DetailText1Opac = 1;

        public int DetailText1Opacity
        {
            get { return this.DetailText1Opac; }
            set
            {
                this.DetailText1Opac = value;
                TextBlock tb = _control.Label.FindName(String.Format("{0}_DetailsText1", _controlName)) as TextBlock;
                tb.Opacity = value;
            }
        }

        // Detail Text Line 2 Opacity
        private int DetailText2Opac = 1;

        public int DetailText2Opacity
        {
            get { return this.DetailText2Opac; }
            set
            {
                this.DetailText2Opac = value;
                TextBlock tb = _control.Label.FindName(String.Format("{0}_DetailsText2", _controlName)) as TextBlock;
                tb.Opacity = value;
            }
        }

        // Detail Text Line 3 Opacity
        private int DetailText3Opac = 1;

        public int DetailText3Opacity
        {
            get { return this.DetailText3Opac; }
            set
            {
                this.DetailText3Opac = value;
                TextBlock tb = _control.Label.FindName(String.Format("{0}_TextDetails3", _controlName)) as TextBlock;
                tb.Opacity = value;
            }
        }

        // Set size of detail text
        private int detailTextSize = 8;

        public int DetailTextSize
        {
            get { return detailTextSize; }
            set
            {
                detailTextSize = value;

                // Set font size for all 3 lines of detail text
                for (int i = 1; i < 4; i++)
                {
                    ((TextBlock)_control.Label.FindName(String.Format("{0}_DetailsText{1}", _controlName, i))).FontSize = detailTextSize;
                }

            }
        }

        // Set size of aspect title text
        private int titleTextSize;

        public int TitleTextSize
        {
            get { return titleTextSize; }
            set
            {
                titleTextSize = value;
                ((TextBlock)_control.Label.FindName(String.Format("{0}_TitleText", _controlName))).FontSize = titleTextSize;
            }
        }



        #endregion

        #region Event Handlers

            // Mouse enters the aspect
            protected void MouseEnterEvent(object o, EventArgs e)
            {
                Canvas AspectCanvas = (Canvas)o;

                // Change cursor to hand
                if (AspectCanvas != null)
                {
                    AspectCanvas.Cursor = Cursors.Hand;

                    // Highlight the aspect
                    Storyboard sb = _control.Image.FindName(String.Format("{0}_AspectHighlight",_controlName)) as Storyboard;
                    ColorAnimation animColor = _control.Image.FindName(String.Format("{0}_AspectHighlightColor",_controlName)) as ColorAnimation;
                    if (sb != null && animColor != null)
                    {
                        animColor.SetValue(ColorAnimation.ToProperty, Colors.Green);
                        sb.Begin();
                    }
                }
            }

            // Mouse leaves the aspect
            protected void MouseLeaveEvent(object o, EventArgs e)
            {
                Canvas AspectCanvas = (Canvas)o;
                
                // Set cursor to arrow
                if (AspectCanvas != null)
                {
                    AspectCanvas.Cursor = Cursors.Arrow;

                    // Unhighlight the aspect
                    Storyboard sb = _control.Image.FindName(String.Format("{0}_AspectHighlight", _controlName)) as Storyboard;
                    ColorAnimation animColor = _control.Image.FindName(String.Format("{0}_AspectHighlightColor", _controlName)) as ColorAnimation;
                    if (sb != null && animColor != null)
                    {
                        animColor.SetValue(ColorAnimation.ToProperty, Colors.White);
                        sb.Begin();
                    }
                }
            }

            void Control_Clicked(object sender, RoutedEventArgs e)
            {
                // Our inner control has been clicked - raise an event to the 360 so that they know which "model" has been selected, 
                // so that the screen can be changed
                NavEventArgs args = new NavEventArgs();

                args.Account = Model;
                AspectClick(this, args);
            }

            void Control_EndDrag(object sender, RoutedEventArgs e)
            {
                contentScreen.FixItemZOrder();
            }

            void Control_BeginDrag(object sender, RoutedEventArgs e)
            {
                ZOrder = 100;
            }

        #endregion

        #region Helper Methods

        /// <summary>
        /// AttachHandlers is used to connect ourselves to the various event handlers we want to use, such as responding to the click event
        /// of the control we wrap, and setting up mouse enter / leave events to provide highlighting when the mouse is over the body
        /// of the control. This used to be done from the constructor, but the control isn't attached to the parent window at that time
        /// and so trying to find the IconBody part of each image we display fails. It is therefore the caller's responsibility to call this
        /// function once the related control is added to the appropriate container as part of the Silverlight tree.
        /// </summary>
        public void AttachHandlers()
        {
            // Connect to events fired by the control we wrap
            _control.Clicked += new RoutedEventHandler(Control_Clicked);
            _control.BeginDrag += new RoutedEventHandler(Control_BeginDrag);
            _control.EndDrag += new RoutedEventHandler(Control_EndDrag);

            // Connect to events fired by the body of the image we display on the control. This is for icon highlighting
            Canvas iconBody = _control.Image.FindName(String.Format("{0}_IconBody", _controlName)) as Canvas;

            if (iconBody != null)
            {
                iconBody.MouseEnter += new MouseEventHandler(MouseEnterEvent);
                iconBody.MouseLeave += new MouseEventHandler(MouseLeaveEvent);
            }
        }

        // Called when the model property is assigned to
        // Used to set the details text beside aspect
        private void SetDetailsText()
        {
            // Find detail textblocks
            TextBlock title = _control.Label.FindName(String.Format("{0}_TitleText", _controlName)) as TextBlock;
            TextBlock detail1 = _control.Label.FindName(String.Format("{0}_DetailsText1", _controlName)) as TextBlock;
            TextBlock detail2 = _control.Label.FindName(String.Format("{0}_DetailsText2", _controlName)) as TextBlock;
            TextBlock detail3 = _control.Label.FindName(String.Format("{0}_DetailsText3", _controlName)) as TextBlock;

            if (title == null || detail1 == null || detail2 == null || detail3 == null)
                return;

            // Set title
            title.Text = _model.Name;

            // For calculating time until due date
            TimeSpan timeTillDue;

            // Set details depending on which account type
            switch (_model.Type)
            {
                case AccountType.Checking:
                    detail1.Text = AppResources.Get("Res_AspectBalance", _model.Balance.ToCurrency());
                    detail2.Text = AppResources.Get("Res_AspectLastTrans", (_model.LastTransactionAmount).ToCurrency());
                    detail3.Text = AppResources.Get("Res_AspectTransDate", _model.LastTransactionDate.ToString("d MMM yy"));
                    break;
                case AccountType.Savings:
                    detail1.Text = AppResources.Get("Res_AspectBalance", _model.Balance.ToCurrency());
                    detail2.Text = "";
                    detail3.Text = "";
                    break;
                case AccountType.CreditCard:
                    detail1.Text = AppResources.Get("Res_AspectBalance", _model.Balance.ToCurrency());
                    detail2.Text = AppResources.Get("Res_AspectNextPayment", _model.NextPaymentAmount.ToCurrency());
                    detail3.Text = AppResources.Get("Res_AspectDueDate", _model.NextPaymentDueDate.ToString("dd MMM yy"));

                    // Set colour of text depending on time until due
                    timeTillDue = _model.NextPaymentDueDate - DateTime.Today;
                    if (timeTillDue.TotalDays < 6)
                    {
                        detail3.Foreground = new SolidColorBrush(Utils.HexToColor("#FF600000"));
                    }
                    else if (timeTillDue.TotalDays > 25)
                    {
                        detail3.Foreground = new SolidColorBrush(Utils.HexToColor("#FF488E48"));
                    }
                    break;
                case AccountType.FiveTwoNine:
                    detail1.Text = AppResources.Get("Res_AspectBalance", _model.Balance.ToCurrency());
                    detail2.Text = "";
                    detail3.Text = "";
                    break;
                case AccountType.Investments:
                    detail1.Text = AppResources.Get("Res_AspectBalance", _model.Balance.ToCurrency());
                    detail2.Text = "";
                    detail3.Text = "";
                    break;
                case AccountType.Mortgage:
                    detail1.Text = AppResources.Get("Res_AspectBalance", _model.Balance.ToCurrency());
                    detail2.Text = AppResources.Get("Res_AspectNextPayment", _model.NextPaymentAmount.ToCurrency());
                    detail3.Text = AppResources.Get("Res_AspectDueDate", _model.NextPaymentDueDate.ToString("dd MMM yy"));

                    // Set colour of text depending on time until due
                    timeTillDue = _model.NextPaymentDueDate - DateTime.Today;
                    if (timeTillDue.TotalDays < 6)
                    {
                        detail3.Foreground = new SolidColorBrush(Utils.HexToColor("#FF600000"));
                    }
                    else if (timeTillDue.TotalDays > 25)
                    {
                        detail3.Foreground = new SolidColorBrush(Utils.HexToColor("#FF488E48"));
                    }
                    break;
                case AccountType.Plan401k:
                    detail1.Text = AppResources.Get("Res_AspectBalance", _model.Balance.ToCurrency());
                    detail2.Text = "";
                    detail3.Text = "";
                    break;
                case AccountType.TradeHistory:
                    detail1.Text = AppResources.Get("Res_AspectValue", _model.Balance.ToCurrency());
                    detail2.Text = "";
                    detail3.Text = "";
                    break;
                default:
                    detail1.Text = "";
                    detail2.Text = "";
                    detail3.Text = "";
                    break;
            }
        }

        #endregion

        #region Events

        public event EventHandler AspectClick;

        #endregion

    }
}
